//
//  DAUPatrolVC.m
//  DAU-iOS
//
//  Created by XiangDongMBP on 2016/11/18.
//  Copyright © 2016年 East. All rights reserved.
//

#import "DAUPatrolVC.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "NSDate+XDTimerFormatter.h"

typedef NS_ENUM(NSInteger, SignState) {
    SignStateNotSign = 0,
    SignStateOnSign,
    SignStateHaveSign
};

@interface DAUPatrolVC () <CBCentralManagerDelegate, CBPeripheralDelegate>

@property (weak, nonatomic) IBOutlet UIButton *patrolBtn;
@property (weak, nonatomic) IBOutlet UITextView *logTextView;

@property (strong, nonatomic) CBCentralManager *manager;
@property (strong, nonatomic) NSTimer *timer;
@property (strong, nonatomic) NSMutableArray<CBPeripheral *> *peripheralMArray;
@property (strong, nonatomic) NSMutableString *logMString;
@property (assign, nonatomic) SignState patrolState;

@end

static NSString *const kServiceUUID = @"FFE0";
static NSString *const kCharacteristicUUID = @"FFE1";
static NSString *const kPeripheralName = @"SU3110";

@implementation DAUPatrolVC

- (void)dealloc {
    // 退出页面之前，一定要断开蓝牙连接，否则再次进入就无法连接了，因为蓝牙模块没有断开连接
    if (_peripheralMArray.count) {
        NSLog(@"销毁界面，断开连接, %@", _peripheralMArray.firstObject);
        [_manager cancelPeripheralConnection:_peripheralMArray.firstObject];
    }
    // 停止扫描
    NSLog(@"销毁界面，停止扫描");
    [_manager stopScan];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    [self initNavigationBar];
    [self initSubViews];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (BOOL)hidesBottomBarWhenPushed {
    return YES;
}

- (NSMutableArray *)peripheralMArray {
    if (!_peripheralMArray) {
        _peripheralMArray = [NSMutableArray array];
    }
    
    return _peripheralMArray;
}

- (NSMutableString *)logMString {
    if (!_logMString) {
        _logMString = [NSMutableString string];
    }
    
    return _logMString;
}

- (void)setPatrolState:(SignState)patrolState {
    _patrolState = patrolState;

    NSArray *array = @[NSLocalizedString(@"点击签到", nil),
                       NSLocalizedString(@"扫描外设中...", nil),
                       NSLocalizedString(@"签到成功", nil)];
    [self.patrolBtn setTitle:array[patrolState] forState:UIControlStateNormal];
}

/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

- (void)initNavigationBar {
    self.navigationItem.title = NSLocalizedString(@"巡更", nil);
}

- (void)initSubViews {
    self.logTextView.hidden = YES;
    
    self.patrolBtn.layer.cornerRadius = 2;
    self.patrolBtn.layer.masksToBounds = YES;
    [self.patrolBtn addTarget:self action:@selector(patrolBtnTapped:) forControlEvents:UIControlEventTouchUpInside];
}

#pragma mark - 按键处理
- (void)patrolBtnTapped:(UIButton *)btn {
    if (!self.manager) {
        self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
        return;
    }
    
    if (self.patrolState == SignStateHaveSign) {
        [MBProgressHUD showPromptWithAutoHideInView:self.view message:NSLocalizedString(@"已签到成功", nil)];
        return;
    }
    
    if (self.patrolState == SignStateOnSign) {
        [MBProgressHUD showPromptWithAutoHideInView:self.view message:NSLocalizedString(@"扫描外设中...", nil)];
        return;
    }
    
    if (self.manager.state == CBCentralManagerStatePoweredOff) {
        [self jumpToOpenBluetooth];
        return;
    }
    
    if (self.patrolState == SignStateNotSign) {
        [self startScanPeripheral];
        return;
    }
}

#pragma mark - <CBCentralManagerDelegate>代理
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    switch (central.state) {
        case CBCentralManagerStateUnknown:
            NSLog(@">>>CBCentralManagerStateUnknown");
            break;
        case CBCentralManagerStateResetting:
            NSLog(@">>>CBCentralManagerStateResetting");
            break;
        case CBCentralManagerStateUnsupported:
            NSLog(@">>>CBCentralManagerStateUnsupported");
            break;
        case CBCentralManagerStateUnauthorized:
            NSLog(@">>>CBCentralManagerStateUnauthorized");
            break;
        case CBCentralManagerStatePoweredOff:
            NSLog(@">>>CBCentralManagerStatePoweredOff");
            [self updateLog:NSLocalizedString(@"蓝牙未打开", nil)];
            [self jumpToOpenBluetooth];
            break;
        case CBCentralManagerStatePoweredOn:
            NSLog(@">>>CBCentralManagerStatePoweredOn");
            [self updateLog:NSLocalizedString(@"蓝牙已打开", nil)];
            [self startScanPeripheral];
            break;
        default:
            break;
    }
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI {
    
    NSLog(@"发现外设%@, id:%@, 服务数组%@, 广播内容:%@", peripheral.name, peripheral.identifier, peripheral.services, advertisementData);
    [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"发现外设(%@)", nil), peripheral.name]];
    
    // 这里不能用peripheral.name，因为iOS会记录上一次连接的名称，当更改了外设name之后，这里还是上一次的名字
    // 后来发现，有的广播包里面不包含CBAdvertisementDataLocalNameKey的name值，所以改为||判断
    if ([advertisementData[CBAdvertisementDataLocalNameKey] hasPrefix:kPeripheralName]
        || [peripheral.name hasPrefix:kPeripheralName]) {
        NSLog(@"连接外设:%@", peripheral.name);
        [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"开始连接外设(%@)", nil), peripheral.name]];
        //找到的设备必须持有它，否则CBCentralManager中也不会保存peripheral，那么CBPeripheralDelegate中的方法也不会被调用！！
        [self.peripheralMArray addObject:peripheral];
        //连接设备
        [central connectPeripheral:peripheral options:nil];
    }
}

- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@">>>连接到名称为（%@）的设备-成功",peripheral.name);
    [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"连接外设(%@)成功", nil), peripheral.name]];
//    // 停止扫描
//    NSLog(@"连接成功，停止扫描");
//    [central stopScan];
    
    //设置的peripheral委托CBPeripheralDelegate
    //@interface ViewController : UIViewController<CBCentralManagerDelegate,CBPeripheralDelegate>
    [peripheral setDelegate:self];
    // 扫描外设Services，成功后会进入方法：-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    // 改为搜索指定的Services的UUID
    [peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
}

- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@">>>连接到名称为（%@）的设备-失败,原因:%@",[peripheral name],[error localizedDescription]);
    [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"连接外设(%@)失败,原因:%@", nil), peripheral.name, error.localizedDescription]];
    self.patrolState = SignStateNotSign;
}

// Peripherals断开连接
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@">>>外设连接断开连接 %@: %@\n", [peripheral name], [error localizedDescription]);
    if (error) {
        // 有错误说明不是手机APP主动断开
        [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"外设(%@)已断开,原因:%@", nil), peripheral.name, error.localizedDescription]];
        self.patrolState = SignStateNotSign;
    }
}

#pragma mark - <CBPeripheralDelegate>代理
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@">>>扫描到服务：%@",peripheral.services);
    if (error) {
        NSLog(@">>>Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]);
        return;
    }
    
    for (CBService *service in peripheral.services) {
        NSLog(@"%@",service.UUID);
        //扫描每个service的Characteristics，扫描到后会进入方法： -(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
        // 改为搜索置顶的characteristic
        [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID]] forService:service];
    }
}

- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
    if (error) {
        NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]);
        return;
    }
    
    for (CBCharacteristic *characteristic in service.characteristics) {
        NSLog(@"service:%@ 的 Characteristic: %@, 权限是%lx",service.UUID, characteristic.UUID, (unsigned long)characteristic.properties);
        if ([service.UUID.UUIDString isEqualToString:kServiceUUID]
            && [characteristic.UUID.UUIDString isEqualToString:kCharacteristicUUID]) {
            
            // 订阅通知(这样当蓝牙外设给我返回数据时，可以接收到)
            [self notifyCharacteristic:peripheral characteristic:characteristic];
            [self updateLog:NSLocalizedString(@"向外设发送签到请求", nil)];
//            NSString * name = [NSString stringWithFormat:@"[NAME]%@[TIME]%zd", [[NSUserDefaults standardUserDefaults] objectForKey:DAU_USERDEF_UNAME], [NSDate timeIntervalSinceReferenceDate]];
            // 是否要加入签到时间
            NSString * name = [NSString stringWithFormat:@"[NAME]%@\r\n", [[NSUserDefaults standardUserDefaults] objectForKey:DAU_USERDEF_UNAME]];
            [self writeCharacteristic:peripheral characteristic:characteristic value:[name dataUsingEncoding:NSUTF8StringEncoding]];
        }
    }
    
    //获取Characteristic的值，读到数据会进入方法：-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    for (CBCharacteristic *characteristic in service.characteristics){
        {
            [peripheral readValueForCharacteristic:characteristic];
        }
    }
    
    //搜索Characteristic的Descriptors，读到数据会进入方法：-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
    for (CBCharacteristic *characteristic in service.characteristics){
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }
}

//获取的charateristic的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //打印出characteristic的UUID和值
    //!注意，value的类型是NSData，具体开发时，会根据外设协议制定的方式去解析数据
    NSLog(@"读取值 ---- characteristic uuid:%@  value:%@",characteristic.UUID, characteristic.value);
    
    //这里当收到[NAME]OK表明签到成功，可以断开连接了
    NSString *result = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
    NSLog(@"收到蓝牙外设的值:%@", result);
    if ([characteristic.UUID.UUIDString isEqualToString:kCharacteristicUUID] && [result hasPrefix:@"[NAME]OK"]) {
        NSString *timeStr = [[NSDate date] xd_yyyyMMddHHmmss];
        [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"%@ 签到成功", nil), timeStr]];
        self.patrolState = SignStateHaveSign;
        [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"断开蓝牙(%@)连接", nil), peripheral.name]];
        
        NSLog(@"签到成功，断开连接");
        [self cancelNotifyCharacteristic:peripheral characteristic:characteristic];
        [self.manager cancelPeripheralConnection:peripheral];
        [self.manager stopScan];
    }
}

//搜索到Characteristic的Descriptors
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    //打印出Characteristic和他的Descriptors
    NSLog(@"characteristic uuid:%@",characteristic.UUID);
    for (CBDescriptor *d in characteristic.descriptors) {
        NSLog(@"Descriptor uuid:%@",d.UUID);
    }
}

//获取到Descriptors的值
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForDescriptor:(CBDescriptor *)descriptor error:(NSError *)error{
    //打印出DescriptorsUUID 和value
    //这个descriptor都是对于characteristic的描述，一般都是字符串，所以这里我们转换成字符串去解析
    NSLog(@"characteristic uuid:%@  value:%@",[NSString stringWithFormat:@"%@",descriptor.UUID],descriptor.value);
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        NSLog(@"写入数据失败, %@", error);
        [self updateLog:[NSString stringWithFormat:NSLocalizedString(@"写数据到外设失败,原因:%@", nil), error.localizedDescription]];
        self.patrolState = SignStateNotSign;
        return;
    }
}

// 设置通知时，是否成功的回调
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    //打印出characteristic的UUID和值
    //!注意，value的类型是NSData，具体开发时，会根据外设协议制定的方式去解析数据
    NSLog(@"收到通知：----- characteristic uuid:%@  value:%@",characteristic.UUID, characteristic.value);
}

#pragma mark - 其它函数
//写数据
-(void)writeCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic value:(NSData *)value{
    //打印出 characteristic 的权限，可以看到有很多种，这是一个NS_OPTIONS，就是可以同时用于好几个值，常见的有read，write，notify，indicate，知知道这几个基本就够用了，前连个是读写权限，后两个都是通知，两种不同的通知方式。
    /*
     typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
     CBCharacteristicPropertyBroadcast												= 0x01,
     CBCharacteristicPropertyRead													= 0x02,
     CBCharacteristicPropertyWriteWithoutResponse									= 0x04,
     CBCharacteristicPropertyWrite													= 0x08,
     CBCharacteristicPropertyNotify													= 0x10,
     CBCharacteristicPropertyIndicate												= 0x20,
     CBCharacteristicPropertyAuthenticatedSignedWrites								= 0x40,
     CBCharacteristicPropertyExtendedProperties										= 0x80,
     CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)		= 0x100,
     CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)	= 0x200
     };
     
     */
    NSLog(@"%lu", (unsigned long)characteristic.properties);
    
    
    //只有 characteristic.properties 有write的权限才可以写
    if(characteristic.properties & CBCharacteristicPropertyWrite){
        /*
         最好一个type参数可以为CBCharacteristicWriteWithResponse或type:CBCharacteristicWriteWithResponse,区别是是否会有反馈
         */
        [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }else{
        NSLog(@"该字段不可写！");
    }
}

- (void)startScanPeripheral {
    [self updateLog:NSLocalizedString(@"扫描外设中...", nil)];
    self.patrolState = SignStateOnSign;
    
    //开始扫描周围的外设
    /*
     第一个参数nil就是扫描周围所有的外设，扫描到外设后会进入
     - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI;
     */
    // 先断开一下扫描，再重新扫描
    [self.manager stopScan];
    CBUUID *uid = [CBUUID UUIDWithString:kServiceUUID];
    NSLog(@"生成的UUID：%@", uid.UUIDString);
    // 发现加UUID的扫描，调试的时候两个模块有的发送的时候带有UUID，有的没有
//    [self.manager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @(YES)}];
    [self.manager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey: @(YES)}];
}

// 订阅Characteristic的通知
//设置通知
-(void)notifyCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic{
    //设置通知，数据通知会进入：didUpdateValueForCharacteristic方法
    [peripheral setNotifyValue:YES forCharacteristic:characteristic];
}

//取消通知
-(void)cancelNotifyCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic{
    [peripheral setNotifyValue:NO forCharacteristic:characteristic];
}

- (void)updateLog:(NSString *)string {
    [self.logMString appendString:[NSString stringWithFormat:@"%@\n", string]];
    [self.logTextView setText:self.logMString];
    self.logTextView.hidden = NO;
}

- (void)jumpToOpenBluetooth {
    
    UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"打开蓝牙允许“DAU”连接到配件", nil)
                                                                     message:nil
                                                              preferredStyle:UIAlertControllerStyleAlert];
    [alertVC addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"知道了", nil) style:UIAlertActionStyleDefault handler:nil]];
    [self presentViewController:alertVC animated:YES completion:nil];
}

@end
